package cn.sylinx.hbatis.ext.starter.common;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;

import cn.sylinx.hbatis.exception.HbatisException;
import cn.sylinx.hbatis.ext.proxy.annotation.Command;
import cn.sylinx.hbatis.ext.proxy.command.CommandRegistry;
import cn.sylinx.hbatis.io.ClasspathResourceScanner;
import cn.sylinx.hbatis.kit.StrKit;
import cn.sylinx.hbatis.log.GLog;
import cn.sylinx.hbatis.plugin.IPlugin;
import cn.sylinx.hbatis.plugin.PluginStarter;

class StarterBean {

	private String config = "/hbatis.properties";
	private Properties p;

	public StarterBean() {
		this(null);
	}

	public StarterBean(String config) {
		if (config != null && !"".equals(config)) {
			this.config = config;
		}
		init();
	}

	private void init() {

		p = new Properties();
		try {
			p.load(StarterBean.class.getResourceAsStream(config));
		} catch (IOException e) {
			// 配置文件未找到
			throw new HbatisException(e);
		}
	}

	public void start() {

		String initKey = "hbatis.init";
		String initStr = p.getProperty(initKey, "false");
		boolean init = Boolean.valueOf(initStr);
		if (!init) {
			GLog.info("hbatis 没有被初始化，请确认hbatis.init=true。");
			return;
		}

		registerCommand(p);

		PluginStarter pluginStarter = create(p);
		pluginStarter.start();

	}

	private PluginStarter create(Properties p) {

		List<IPlugin> pluginList = new PluginBuilder(new PropertiesEnvironment(p)) // 插件构建器
				.initDataSourcePlugin() // 初始化数据源
				.initModelPreLoadPlugin() // 模型预加载
				.initSqlResourcePreloadPlugin() // sql资源预加载
				.initStatementHandlerPlugin() // sql语句处理器
				.initTransactionPlugin() // 事务级别插件
				.initCachePlugin() // 缓存插件
				.initProxyPlugin() // 代理插件（第三方）
				.initDebugPlugin() // 是否启动调试
				.build();

		PluginStarter pluginStarter = new PluginStarter(pluginList);
		return pluginStarter;
	}

	private void registerCommand(Properties p) {

		// Command 扫描包，如果为空，则全项目扫描
		String commandScanPackage = Optional.ofNullable(p.getProperty("hbatis.command.scanpackage")).orElse("");
		if (StrKit.isBlank(commandScanPackage)) {
			GLog.warn("hbatis.command.scanpackage没有配置，这将导致花费更多时间扫描整个项目");
		}
		GLog.info("扫描包:{}, 寻找@Command对象", StrKit.isBlank(commandScanPackage) ? "整个项目" : commandScanPackage);

		Set<String> clzSets = new HashSet<>(16);
		// 扫码所有class，寻找Command注解
		ClasspathResourceScanner cp = new ClasspathResourceScanner(commandScanPackage, ".class", true);
		List<String> rList = null;
		try {
			rList = cp.getResourceNameList();
		} catch (Exception e) {
			GLog.error("scan error", e);
		}

		if (rList == null) {
			rList = new ArrayList<String>();
		}

		for (String rs : rList) {
			if (commandScanPackage == "") {
				rs = rs.substring(1);
			}
			String pt1 = rs.replaceAll("/", "\\.");
			int index = pt1.lastIndexOf(".class");
			pt1 = pt1.substring(0, index);
			clzSets.add(pt1);
		}

		if (clzSets == null || clzSets.isEmpty()) {
			return;
		}

		for (String clzStr : clzSets) {
			try {
				Class<?> clz = Class.forName(clzStr);
				Command command = clz.getDeclaredAnnotation(Command.class);

				if (clz.isInterface() && clz.getSuperclass() == null && command != null) {
					GLog.info("注册Command对象:{}", clz.getName());
					CommandRegistry.INSTANCE.addCommond(clz);
				}

			} catch (Throwable e) {
				// do nothing
				GLog.error("register error", e);
			}
		}

		GLog.info("寻找@Command对象完毕，总计:{}", CommandRegistry.INSTANCE.getCommands().size());
	}

}
